<?php
/**
 * MineAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using MineAdmin.
 *
 * @Author X.Mo<root@imoi.cn>
 * @Link   https://gitee.com/xmo/MineAdmin
 */

declare(strict_types=1);

namespace Newbie;

use App\Admin\Service\Setting\SettingConfigService;
use League\Flysystem\Filesystem;
use newbie\Event\UploadAfter;
use Newbie\exception\NormalStatusException;
use Newbie\Helper\Id;
use Newbie\helper\Str;
use Psr\Container\ContainerInterface;
use Shopwwi\WebmanFilesystem\Facade\Storage;
use Shopwwi\WebmanFilesystem\FilesystemFactory;
use Webman\Http\UploadFile;


class NewbieUpload {

    /**
     * @var Filesystem
     */
    protected Filesystem $filesystem;


    /**
     * @var ContainerInterface
     */
    protected ContainerInterface $container;

    /**
     * 存储配置信息
     * @var array
     */
    protected array $config = [];

    /**
     * NewbieUpload constructor.
     */
    public function __construct () {
        $this->container  = container();
        $this->filesystem = FilesystemFactory::get($this->getStorageMode());
    }

    /**
     * 获取文件操作处理系统
     * @return Filesystem
     */
    public function getFileSystem (): Filesystem {
        return $this->filesystem;
    }

    /**
     * 上传文件
     * @param UploadFile $uploadedFile
     * @param array $config
     * @return array
     */
    public function upload (UploadFile $uploadedFile, array $config = []): array {
        return $this->handleUpload($uploadedFile, $config);
    }

    /**
     * 处理上传
     * @param UploadFile $uploadedFile
     * @param array $config
     * @return array
     */
    protected function handleUpload (UploadFile $uploadedFile, array $config): array {
        $path        = $this->getPath($config['path'] ?? null);
        $storageMode = $this->getStorageMode();
        // upload 上传第二参数默认为true即允许相同文件的上传 为false时将会覆盖原文件
        //单文件判断
        try {
            $result = Storage::adapter($this->getStorageMode())->path($path)->upload($uploadedFile);//->size(1024*1024*5)->extYes(['image/jpeg','image/gif'])->extNo(['image/png'])
        } catch (\Exception $e) {
            throw new NormalStatusException($e->getMessage());
        }
        //        //多文件上传
        //        $files = $request->file();
        //        $result = Storage::uploads($files);
        //        try {
        //            //uploads 第二个参数为限制文件数量 比如设置为10 则只允许上传10个文件 第三个参数为允许上传总大小 则本列表中文件总大小不得超过设定 第四参数默认为true即允许同文件上传 false则为覆盖同文件
        //            $result = Storage::adapter('public')->path('storage/upload/user')->size(1024*1024*5)->extYes(['image/jpeg','image/gif'])->extNo(['image/png'])->uploads($files,10,1024*1024*100);
        //        }catch (\Exception $e){
        //            $e->getMessage();
        //        }
        ### 响应字段

        /*        | 字段          |     描述           |  示例值                                                          |
        |-------------|---------------|---------------------------------------------------------------|
        | origin_name | 源文件名称         | webman.png                                                    |
        | file_name   | 文件路径及名称       | storage/a4bab140776e0c1d57cc316266e1ca05.png                  |
        | storage_key | 文件随机key       | a4bab140776e0c1d57cc316266e1ca05                              |
        | file_url    | 文件访问外网        | //127.0.0.1:8787/storage/cab473e23b638c2ad2ad58115e28251c.png |
        | size        | 文件大小          | 22175                                                         |
        | mime_type   | 文件类型          | image/jpeg                                                    |
        | extension   | 文件尾缀          | jpg                                                           |
        | width       | 图片宽度（图片类型才返回） | 206                                                           |
        | height      | 图片高度（图片类型才返回）        | 206        */

        $fileInfo = [
            'storage_mode' => $storageMode,
            'origin_name'  => $result->origin_name,
            'object_name'  => $result->file_name,
            'mime_type'    => $result->mime_type,
            'storage_path' => $path,
            'suffix'       => Str::lower($result->extension),
            'size_byte'    => $uploadedFile->getSize(),
            'size_info'    => format_size($uploadedFile->getSize() * 1024),
            'url'          => $result->file_url,
        ];

        event('UploadAfter', new UploadAfter($fileInfo));

        return $fileInfo;
    }

    /**
     * 获取编码后的文件名
     * @return string
     */
    public function getNewName (): string {
        return (string)container()->get(Id::class)->generate();
    }

    /**
     * 保存网络图片
     * @param array $data
     * @return array
     */
    public function handleSaveNetworkImage (array $data): array {
        $path     = $this->getPath($data['path']);
        $filename = $this->getNewName() . '.jpg';

        try {
            $content = file_get_contents($data['url']);
            $handle  = fopen($data['url'], 'rb');
            $meta    = stream_get_meta_data($handle);
            fclose($handle);

            $dataInfo = $meta['wrapper_data']['headers'] ?? $meta['wrapper_data'];
            $size     = 0;

            foreach ($dataInfo as $va) {
                if (preg_match('/length/iU', $va)) {
                    $ts   = explode(':', $va);
                    $size = intval(trim(array_pop($ts)));
                    break;
                }
            }
            $this->filesystem->write($path . '/' . $filename, $content);
        } catch (\Throwable $e) {
            throw new NormalStatusException($e->getMessage(), 500);
        }
        $fileInfo = [
            'storage_mode' => $this->getStorageMode(),
            'origin_name'  => md5((string)time()) . '.jpg',
            'object_name'  => $filename,
            'mime_type'    => 'image/jpg',
            'storage_path' => $path,
            'suffix'       => 'jpg',
            'size_byte'    => $size,
            'size_info'    => format_size($size * 1024),
            'url'          => Storage::adapter($this->getStorageMode())->url($path . '/' . $filename),
        ];
        event('UploadAfter', new UploadAfter($fileInfo));
        return $fileInfo;
    }

    /**
     * @param string $config
     * @return string
     */
    protected function getPath (?string $path = null): string {
        $uploadfile = env('UPLOAD_PATH', 'upload') . '/';
        return $uploadfile . (empty($path) ? date('Ymd') : $path);
    }

    /**
     * 创建目录
     * @param string $name
     */
    public function createUploadDir (string $name) {
        $this->filesystem->createDirectory($name);
    }

    /**
     * 获取目录内容
     * @param string $path
     * @return \League\Flysystem\DirectoryListing
     */
    public function listContents (string $path = ''): array {
        return $this->filesystem->listContents($path)->toArray();
    }

    /**
     * 获取目录
     * @param string $path
     * @param bool $isChildren
     * @return array
     */
    public function getDirectory (string $path, bool $isChildren): array {
        $contents = $this->filesystem->listContents($path, $isChildren);
        $dirs     = [];
        foreach ($contents as $content) {
            if ($content['type'] == 'dir') {
                $dirs[] = $content;
            }
        }
        return $dirs;
    }

    /**
     * 获取存储方式
     * @return string
     */
    public function getStorageMode (): string {
        return $this->container->get(SettingConfigService::class)->getConfigByKey('site_storage_mode')['value'] ?? 'local';
    }

    /**
     */
    protected function getProtocol (): string {
        return \request()->getScheme();
    }
}